package com.rrd.dw.mr.gzip.bhzx;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer.Context;

import com.rrd.dw.utils.DateUtil;
import com.rrd.dw.utils.MD5Util;

/**
 * 处理垫付结清的数据
 *垫付结清之前，按理财应还日期+宽限期次日报逾期，垫付结清时间点则报“垫付结清”后续不再上报
 * @author liubaoxin
 * 2018-12-26
 */
public class BHZXAdvancePayoffUtils2 {
	public static final String CRT_FLAG = "\001";
    public static final Pattern CRT_PATTERN = Pattern.compile(CRT_FLAG);
    private static NullWritable key_null = NullWritable.get();
	private static Text val_Text = new Text();
	private final static int K=10;
    /**
     * 垫付结清数据(2018-12-26 v)
     * @param context
     * @param map
     * @throws InterruptedException 
     * @throws IOException 
     */
	public static void act_payoff(Context context,List<Map<String,String>> list_map) throws IOException, InterruptedException{
		String target_repayment_date="";
		String target_repayment_date_k="";
		String payoff_date="";
		int term_no=0;
		String next_target_repayment_date_k=null;
		String min_date="";
		String advance_payoff_time=null;
		List<String> list = new ArrayList<String>();
		String dt="";
		for(Map<String,String> map:list_map){ 
			 
			try{
			dt = map.get("dt");
			payoff_date=BHZXUtils.time_to_date(map.get("payoff_time")); 
			target_repayment_date=BHZXUtils.time_to_date(map.get("target_repayment_date"));
			target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(target_repayment_date,"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
			if(!map.get("next_due_date").equals("")){
				next_target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(map.get("next_due_date"),"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
			}
			advance_payoff_time=BHZXUtils.time_to_date(map.get("advance_payoff_time"));
			term_no=Integer.parseInt(map.get("term_no"));
//			System.out.println(map.get("loan_id")+","+map.get("target_repayment_date")+","+map.get("payoff_time")+","+payoff_date+","+target_repayment_date_k);
			if(target_repayment_date.compareTo(dt)>=0 && (payoff_date.equals("") || payoff_date.compareTo(dt)>=0) ){
				context.getCounter("state","normal.records").increment(1);
				min_date="";
				process_normal_pass(context,list_map,map);
				continue;
			}
			//提前还款、正常还款的情况
			if(!payoff_date.equals("") && payoff_date.compareTo(target_repayment_date_k)<0){
				context.getCounter("state","normal.records").increment(1);
				min_date="";
				process_normal(context,list_map,map);
				
			}else  {
				context.getCounter("state","overdue.records").increment(1);
				//逾期情况 
				if(min_date.equals("")){
					min_date=map.get("target_repayment_date");
				} 
				//判断是否垫付结清，并且垫付结清时间在该期的账期内
				if(!advance_payoff_time.equals("") && ((advance_payoff_time.compareTo(target_repayment_date)<=0 && term_no==1) 
					|| (advance_payoff_time.compareTo(target_repayment_date)>=0 && advance_payoff_time.compareTo(next_target_repayment_date_k)<0))){
					min_date="";
					process_advanceoff(context,list_map,map);
					
					break;
				} 
				//应还款日+宽限期次日上报
				//判断如果在“应还款日+宽限期次日”有实际还款记录则不进行“应还款日+宽限期次日”上报
				if(!payoff_date.equals("")){
					list.add(map.get("payoff_time")+","+map.get("next_payoff_time")+","+map.get("planned_payment")+","+map.get("term_no"));
				} 
				if(!isExists(target_repayment_date_k,list)){
					process_overdue_day(context,list_map,map,min_date);
				}
				//处理逾期还款记录的情况
				min_date=process_overdue_pay(context, list_map, map, list, min_date); 
				
			 
				//逾期垫付时间在最后一期应还日之后进行垫付
				if(!advance_payoff_time.equals("") &&  advance_payoff_time.compareTo(target_repayment_date)>0 && term_no==Integer.parseInt(map.get("last_period"))){
					min_date="";
					process_advanceoff(context,list_map,map);
					break;
				}
				
			}
			
			}catch(Exception e){
				System.out.println("-------------------"+map.get("next_payoff_time"));
				context.getCounter("error","act_payoff.err").increment(1);
				throw e;
		}  
		}
	}
	private static boolean isExists(String target_repayment_date_k,List<String> list){
		boolean bool=false;
		for(String s:list){
			if(target_repayment_date_k.equals(BHZXUtils.time_to_date(s.split(",")[0]))){
				bool=true;
			}
		}
		return bool;
	}
	/**
	 * 处理正常还款、提前还款场景
	 * @param context
	 * @param list_maps
	 * @param act_payoff_time
	 * @param term_no
	 * @param act_term_no
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static void process_normal(Context context,List<Map<String,String>> list_maps,Map<String,String> map) throws IOException, InterruptedException{
			double arr[]=null;
			int term_no = Integer.parseInt(map.get("term_no"));
			int old_days=0;
			String act_payoff_date=BHZXUtils.time_to_date(map.get("payoff_time"));
			arr = getLoan_due_amt(list_maps, term_no, term_no, act_payoff_date);
			map.put("target_repayment", String.valueOf(arr[0]));
			map.put("remaining_amount", String.valueOf(arr[1]));
			map.put("real_repayment", String.valueOf(arr[2]));
			map.put("overdue_amount", String.valueOf(arr[3])); //当 前 逾期总额 
			map.put("term_status","normal");
			map.put("real_repayment_date",map.get("payoff_time")); //实际还款时间
			map.put("overdue_status","");
			map.put("status_confirm_at",map.get("payoff_time"));
			if(term_no==Integer.parseInt(map.get("last_period")) && old_days<=0){
				map.put("loan_status", "3");
			}else if(old_days<=0) {
				map.put("loan_status", "1");
			}else{
				map.put("loan_status", "2");
			};
			val_Text.set(BHZXUtils.processToString(map));
			context.write(key_null, val_Text);
		
	}
	private static void process_normal_pass (Context context,List<Map<String,String>> list_maps,Map<String,String> map) throws IOException, InterruptedException{
		int term_no = Integer.parseInt(map.get("term_no"));
		int old_days=0;
		double remain_amt = getLoan_remain_amt(list_maps);
		map.put("target_repayment", "0");
		map.put("target_repayment",map.get("planned_payment"));
		map.put("remaining_amount", String.valueOf(remain_amt));
		map.put("real_repayment", "0");
		map.put("overdue_amount", "0"); //当 前 逾期总额 
		map.put("term_status","normal");
		map.put("real_repayment_date",map.get("payoff_time")); //实际还款时间
		map.put("overdue_status","");
		map.put("status_confirm_at",map.get("payoff_time"));
		if(term_no==Integer.parseInt(map.get("last_period")) && old_days<=0){
			map.put("loan_status", "3");
		}else if(old_days<=0) {
			map.put("loan_status", "1");
		}else{
			map.put("loan_status", "2");
		};
		val_Text.set(BHZXUtils.processToString(map));
		context.write(key_null, val_Text);
	
}
	/**
	 * 处理逾期场景,逾期还款，并且还款时间在“本期还款+宽限期”和“下一期应还款+宽限期”之间
	 * @param context
	 * @param list_maps
	 * @param map
	 * @param min_date
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static String process_overdue_pay(Context context,List<Map<String,String>> list_maps,Map<String,String> map,List<String> list,String min_due_date) throws IOException, InterruptedException{
			double arr[]=null;
			String arrstr[]=null;
			String target_repayment_date="";
			String next_target_repayment_date_k="";
			target_repayment_date=BHZXUtils.time_to_date(map.get("target_repayment_date"));
			String target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(target_repayment_date,"yyyy-MM-dd"), K+1),"yyyy-MM-dd") ;
			if(!map.get("next_due_date").equals("")){
				next_target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(map.get("next_due_date"),"yyyy-MM-dd"), K+1),"yyyy-MM-dd") ;
			} 
			
			//观察日
			String payoff_date=""; 
			String next_payoff_date=""; 
			int old_days=0;
			int act_term_no=0;
			for(String s:list){
				arrstr=s.split(",");
				payoff_date=BHZXUtils.time_to_date(arrstr[0]);
				next_payoff_date=BHZXUtils.time_to_date(arrstr[1]);
				act_term_no=Integer.parseInt(arrstr[3]);
				if(payoff_date.compareTo(target_repayment_date_k)>=0
						&& (next_target_repayment_date_k.equals("") || payoff_date.compareTo(next_target_repayment_date_k)<0  )){
					 //在该账期内的还款
					if(payoff_date.equals(next_payoff_date)){
						continue;
					}
					if(payoff_date.equals(BHZXUtils.time_to_date(map.get("payoff_time")))){
						old_days=0;
						min_due_date="";
					}else{
//						System.out.println("loan_id="+map.get("loan_id")+",payoff_time="+map.get("payoff_time")+",confirm_at="+confirm_at+",min_due_date=>"+min_due_date);
						if(min_due_date.equals("")){
							old_days=0;
						}else{
							old_days=DateUtil.date_diff(payoff_date, min_due_date);
						}
						
					}
					arr = getLoan_due_amt(list_maps, Integer.parseInt(map.get("term_no")), act_term_no, payoff_date);
					map.put("target_repayment", String.valueOf(arr[0]));
					map.put("remaining_amount", String.valueOf(arr[1]));
					map.put("real_repayment", String.valueOf(arr[2]));
					map.put("overdue_amount", String.valueOf(arr[3])); //当 前 逾期总额 
					map.put("term_status",old_days>K?"overdue":"normal");
					map.put("real_repayment_date",arrstr[0]); //实际还款时间
					map.put("overdue_status",old_days>K?"D"+old_days:"");
					map.put("status_confirm_at",arrstr[0]);
					if(map.get("last_due_date").equals(map.get("target_repayment_date")) &&  old_days<=0){
						map.put("loan_status", "3"); 
					}else if(old_days>K){
						map.put("loan_status", "2");
					}else{
						map.put("loan_status", "1");
					} 
					val_Text.set(BHZXUtils.processToString(map));
					context.write(key_null, val_Text);
					
				}
			}
			return min_due_date;
			
				
	}
	/**
	 * 处理逾期场景，逾期+宽限期次日上报
	 * @param context
	 * @param list_maps
	 * @param map
	 * @param min_date
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static void process_overdue_day(Context context,List<Map<String,String>> list_maps,Map<String,String> map,String min_date) throws IOException, InterruptedException{
			double arr[]=null;
			String target_repayment_date="";
			String target_repayment_date_k="";
			target_repayment_date=BHZXUtils.time_to_date(map.get("target_repayment_date"));
			target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(target_repayment_date,"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
			//观察日
			String status_confirm_at=target_repayment_date_k; 
			int old_days=0;
			
			old_days=DateUtil.date_diff(status_confirm_at,min_date );
			arr = getLoan_due_amt(list_maps, Integer.parseInt(map.get("term_no")), 0, "no");
			map.put("target_repayment", String.valueOf(arr[0]));
			map.put("remaining_amount", String.valueOf(arr[1]));
			map.put("real_repayment", String.valueOf(arr[2]));
			map.put("overdue_amount", String.valueOf(arr[3])); //当 前 逾期总额 
			map.put("term_status","overdue");
			map.put("real_repayment_date",""); //实际还款时间
			map.put("overdue_status","D"+old_days);
			map.put("status_confirm_at",status_confirm_at);
			map.put("loan_status", "2");
			val_Text.set(BHZXUtils.processToString(map));
			context.write(key_null, val_Text);
				
	}
	private static void process_overdue(Context context,List<Map<String,String>> list_maps,String min_date,String act_payoff_time,int act_term_no) throws IOException, InterruptedException{
		double arr[]=null;
		String target_repayment_date="";
		String next_target_repayment_date_k=null;
		int term_no=0;
		String act_payoff_date=BHZXUtils.time_to_date(act_payoff_time);
		int old_days=0;
		
		for(Map<String,String> map :list_maps){
			target_repayment_date=BHZXUtils.time_to_date(map.get("target_repayment_date"));
			next_target_repayment_date_k=DateUtil.formateDateStr(DateUtil.addDay(DateUtil.formateToDate(map.get("next_due_date"),"yyyy-MM-dd"), K+1),"yyyy-MM-dd");
			
			//根据还款时间，判定本次还款进件所在期数
			if(act_payoff_date.compareTo(target_repayment_date)>=0 && act_payoff_date.compareTo(next_target_repayment_date_k)<0){
				term_no=Integer.parseInt(map.get("term_no"));
				if(min_date.equals("")){
					old_days=0;
				}else{
					old_days=DateUtil.date_diff(act_payoff_date, min_date);
				}
				
				arr = getLoan_due_amt(list_maps, term_no, act_term_no, act_payoff_date);
				
				map.put("target_repayment", String.valueOf(arr[0]));
				map.put("remaining_amount", String.valueOf(arr[1]));
				map.put("real_repayment", String.valueOf(arr[2]));
				map.put("overdue_amount", String.valueOf(arr[3])); //当 前 逾期总额 
				map.put("term_status",old_days>0?"overdue":"normal");
				map.put("real_repayment_date",act_payoff_time); //实际还款时间
				map.put("overdue_status",old_days>0?"D"+old_days:"");
				map.put("status_confirm_at",act_payoff_time);
				map.put("overdue_amount", String.valueOf(0)); //当 前 逾期总额
				map.put("req_id", MD5Util.getMd5(map.get("repay_plan_key")+map.get("status_confirm_at")+map.get("term_status"))); 
				if(term_no==Integer.parseInt(map.get("last_period")) && old_days<=0){
					map.put("loan_status", "3");
				}else if(old_days<=0) {
					map.put("loan_status", "1");
				}else{
					map.put("loan_status", "2");
				};
				
				val_Text.set(BHZXUtils.processToString(map));
				context.write(key_null, val_Text);
			    break;	
			}
			
		}
	}
	/**
	 * 处理垫付结清场景
	 * @param context
	 * @param list_maps
	 * @param min_date
	 * @param act_payoff_time
	 * @param act_term_no
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static void process_advanceoff(Context context,List<Map<String,String>> list_maps,Map<String,String> map) throws IOException, InterruptedException{
		String advance_payoff_time=map.get("advance_payoff_time");
		double act_amt=0;
		for(Map<String,String> m:list_maps){
			if(!m.get("is_true").equals("true")){
				act_amt=act_amt+Double.parseDouble(m.get("planned_payment"));
				m.put("is_true", "true");
			}
		}
			//根据还款时间，判定本次还款进件所在期数
			map.put("target_repayment", String.valueOf(act_amt));
			map.put("remaining_amount","0");
			map.put("real_repayment", String.valueOf(act_amt));
			map.put("overdue_amount", "0"); //当 前 逾期总额 
			map.put("term_status","normal");
			map.put("real_repayment_date",advance_payoff_time); //实际还款时间
			map.put("overdue_status","");
			map.put("status_confirm_at",advance_payoff_time);
			map.put("overdue_amount", "0"); //当 前 逾期总额
			map.put("loan_status", "3");
				
			val_Text.set(BHZXUtils.processToString(map));
			context.write(key_null, val_Text);
			   
	} 

	//计算当期剩余应还款金额、借款剩余余额、本次实际还款金额
		private static double[] getLoan_due_amt(List<Map<String,String>> list_maps,int term_no,int act_term_no,String act_payoff_date){
				double loan_due_amt=0;
				String payoff_date="";
				double remain_amt=0;
				double[] arr=new double[4];
				double act_amount=0;
				double overdue_amount=0;
				for(Map<String,String> m :list_maps){
					payoff_date=BHZXUtils.time_to_date(m.get("payoff_time"));
					if(Integer.parseInt(m.get("term_no"))<=term_no && !m.get("is_true").equals("true")){
						loan_due_amt=loan_due_amt+Double.parseDouble(m.get("planned_payment"));
						
					}
					if(payoff_date.equals(act_payoff_date) && Integer.parseInt(m.get("term_no"))<=act_term_no && !m.get("is_true").equals("true")){
						act_amount=act_amount+Double.parseDouble(m.get("planned_payment"));
						m.put("is_true", "true");
					}
					if(!m.get("is_true").equals("true")){
						remain_amt=remain_amt+Double.parseDouble(m.get("planned_payment"));
					}
					if(Integer.parseInt(m.get("term_no"))<=term_no && !m.get("is_true").equals("true")){
						overdue_amount=overdue_amount+Double.parseDouble(m.get("planned_payment"));;
						
					}
					
	             }
				arr[0]=loan_due_amt;
				arr[1]=remain_amt;
				arr[2]=act_amount;
				arr[3]=overdue_amount;
				return arr;
			}
		private static double getLoan_remain_amt(List<Map<String,String>> list_maps){
 
			double remain_amt=0;
			 
			for(Map<String,String> m :list_maps){
				 
				if(!m.get("is_true").equals("true")){
					remain_amt=remain_amt+Double.parseDouble(m.get("planned_payment"));
				}
				 
				
             }
			 
			return remain_amt;
		}
	 
}
